package com.eci.common.util;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.Optional;
import java.util.List; 

/***
 * 	一个计算工具类
 * 	(时间加减,数字加减乘除等等)
 * */
public class CalcUtil {
	
	private static final int DEF_DIV_SCALE = 10;  
	
	private CalcUtil(){
		
	}
	
	/**
	 * 	日期(不带时间) 加上d天后的日期(d为负 表示减)
	 * @param date
	 * @param d
	 * @return
	 * */
	public static LocalDate getDateAfterAddDays(LocalDate date, int d) {
		return  Optional.of(date).get().plusDays(d); 
	}
	
	/**
	 *	 日期(带时间) 加上d天后的时间(d为负 表示减)
	 * @param date
	 * @param d
	 * @return
	 * */
	public static LocalDateTime getDateTimeAfterAddDays(LocalDateTime datetime, int d) {
		return  Optional.of(datetime).get().plusDays(d); 
	}
	
	/**
	 * 	日期(不带时间) 加上m月后的时间(m为负 表示减)
	 * @param date
	 * @param m
	 * @return
	 * */
	public static LocalDate getDateAfterAddMonths(LocalDate date, int d) {
		  
		 return Optional.of(date).get().plusMonths(d);
		
	}
	
	/**
	 * 	日期(带时间) 加上m月后的时间(m为负 表示减)
	 * @param date
	 * @param m
	 * @return
	 * */
	public static LocalDateTime getDateTimeAfterAddMonths(LocalDateTime datetime, int d) {
		  
		 return Optional.of(datetime).get().plusMonths(d);
		
	}
	
	
    /**
     * 	给定2个日期 相差的年份，后者减前者
     * @param dt
     * @return
    */
    public static int getBetweenYears(LocalDate before,LocalDate after) {
    	
       return Optional.of(after).get().getYear() - Optional.of(before).get().getYear();
       
    }
	
	/**
	 *	 获取日期的所在月份的第一天
	 * 	返回 yyyy-MM-dd 格式的日期
	 * @param date
	 * @return
	 * */
	public static LocalDate getFirstDayOfMonth(LocalDate localDate) {
		
		return Optional.of(localDate).get().with(TemporalAdjusters.firstDayOfMonth());
		
	}
	
	/**
	 *	获取日期的所在月份的最后一天
	 * 	返回 yyyy-MM-dd 格式的日期
	 * @param date
	 * @return
	 * */
	public static LocalDate getLastDateOfMonth(LocalDate localDate) {
		
		return Optional.of(localDate).get().with(TemporalAdjusters.lastDayOfMonth());
		
	}
	
	/**
	  *	计算2个时间相隔的多少秒 小的在前 大的在后
	  */
	public static long separatSeconds(LocalDate d, LocalDate x){
		
		Duration dt = Duration.between(Optional.of(d).get(),Optional.of(x).get());
		
		return dt.toMillis()/1000;
		
	}
	
	/**
	  *	计算2个时间相隔的多少秒 小的在前 大的在后
	  */
	public static long separatSeconds(LocalDateTime d, LocalDateTime x){
		
		Duration dt = Duration.between(Optional.of(d).get(),Optional.of(x).get());
		
		return dt.toMillis()/1000;
		
	}
	/**
	  *	计算2个时间相隔的多少秒 小的在前 大的在后
	  */
	public static long separatSeconds(LocalTime d, LocalTime x){
		
		Duration dt = Duration.between(Optional.of(d).get(),Optional.of(x).get());
		
		return dt.toMillis()/1000;
		
	}
	
	/**
	 * 	提供精确的加法运算。 
     *  
     * @param b1  被加数 
     * @param b2   加数 
     * @return 两个参数的和 
     */  
    public static BigDecimal add(BigDecimal b1, BigDecimal b2) {   
        return Optional.of(b1).get().add(Optional.of(b2).get());  
    }  
  
    /** 
     * 	提供精确的减法运算。 
     *  
     * @param b1   被减数 
     * @param b2   减数 
     * @return 两个参数的差 
     */  
    public static BigDecimal sub( BigDecimal b1,  BigDecimal b2) {
    	
        return Optional.of(b1).get().subtract(Optional.of(b2).get());  
    }  
  
    /**
     * 	 提供精确的乘法运算。 
     *  
     * @param b1   被乘数 
     * @param b2  乘数 
     * @return 两个参数的积 
     */  
    public static BigDecimal mul(BigDecimal b1, BigDecimal b2) {  
         
        return Optional.of(b1).get().multiply(Optional.of(b2).get());  
    }  
  
    /** 
     * 	提供（相对）精确的除法运算，当发生除不尽的情况时，精确到 小数点以后10位，以后的数字四舍五入。 
     *  
     * @param b1  被除数 
     * @param b2   除数 
     * @return 两个参数的商 
     */  
    public static BigDecimal div(BigDecimal b1, BigDecimal b2) {  
        return div(b1, b2, DEF_DIV_SCALE);  
    }  
  
    /**
     *	提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字四舍五入。 
     *  
     * @param b1  被除数 
     * @param b2  除数 
     * @param scale   表示表示需要精确到小数点以后几位。 
     * @return 两个参数的商 
     */  
    public static BigDecimal div(BigDecimal b1, BigDecimal b2, int scale) {  
        if (scale < 0) {  
            throw new IllegalArgumentException("The scale must be a positive integer or zero");  
        }   
        return Optional.of(b1).get().divide(Optional.of(b2).get(), scale, BigDecimal.ROUND_HALF_UP);  
    }  
  
    /**
     * 	提供精确的小数位四舍五入处理。 
     *  
     * @param b  需要四舍五入的数字 (为null时，返回也是null)
     * @param scale  小数点后保留几位 
     * @return 四舍五入后的结果 
     */  
    public static BigDecimal round(BigDecimal b, int scale) {
    	return Optional.ofNullable(b).isPresent()?b.setScale(2, BigDecimal.ROUND_HALF_UP):null;
    }  

	/**
	 * 	计算得到一个长度为4位的十六进制字符串相反字符串(结果大写)。<br>
	 *	将一个长度为4位的十六进制字符串转换成一个新的长度为4的十六进制字符串。<br>
	 *  2个十六进制字符串的关系是他们的二进制的第一位是相反关系，其他位一样。<br>
	 *	如： 3002  --> 0011 0000 0000 0010  <br>
	 *	返回  B002  --> 1011 0000 0000 0010 
	 *  
	 * @param hex     代计算的4位十六进制字符串
	 * @return 新的长度为4的十六进制字符串
	 */
    public static String  getOppHex(String hex) {
    	 
    	String calcVal=Integer.toHexString(Integer.parseInt(hex, 16)+32768).toUpperCase();
    	
    	if(calcVal.length()>4) { 
    		calcVal=calcVal.substring(calcVal.length()-4);
    	}
    	
    	return calcVal;
    }
     
	/**
	 *	判断一个数值型集合元素内的元素是否是持续变大<br>（含相等，即后一个大于等于前一个的值）。<br> 
	 *  
	 * @param list	数值型集合
	 * @return 
	 */
    public static boolean  IsAlwaysRaise(List<BigDecimal> list) {
    	
    	if(list==null || list.isEmpty()) {
    		return false;
    	}
    	boolean rt = true;
    	BigDecimal prev = list.get(0); 
    	for(BigDecimal v :list) {
    		if(v.compareTo(prev) < 0) {
    			rt= false;
    			break;
    		}
    		prev = v; 
    	}
    	
    	return rt;
    }
    
	/**
	 *	判断一个数值型集合元素内的元素是否是持续变小<br>（含相等，即后一个小于等于前一个的值）。<br> 
	 *  
	 * @param list	数值型集合
	 * @return 
	 */
    public static boolean  IsAlwaysReduce(List<BigDecimal> list) {
    	
    	if(list==null || list.isEmpty()) {
    		return false;
    	}
    	boolean rt = true;
    	BigDecimal prev = list.get(0); 
    	for(BigDecimal v :list) {
    		if(v.compareTo(prev) > 0) {
    			rt= false;
    			break;
    		}
    		prev = v; 
    	}
    	
    	return rt;
    }
    
    /*** 将【2个字节】的十六进制字符串转换成非负整数<br>
     *	字符串长度为4,最小为"0000",最大为"ffff"
     *  @hex 十六进制字符串  （要求是合法非负整数型）
     *  @return 大于等于0即是正确结果，-1则是表示转换出错
     * */
    public static int transformHex(String hex) {
    	int i= -1;
    	if(hex==null || hex.length()!=4) {
    		return i;
    	}
    	
    	try {
			i=Integer.parseInt(hex, 16);
		} catch (NumberFormatException e) { 
			e.printStackTrace();
		}
    	return  i;
    }
    
    
    /*** 非负整数 转换成【2个字节】十六进制字符串
     *  @number 输入参数  （最小为0,最大为65535）
     *  @return null则是表示转换出错，否则反之。
     * */
    public static String transformInt(int number) {
    	if(number>65535 || number<0 ) {
    		return null;
    	}
    	return String.format("%04x",number);
    	
    }
     
    
}
